// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-11-19

package common

import (
	"context"
	"gitee.com/go-libs/log/base"
	"sync"
	"time"
)

var itemPool = sync.Pool{
	New: func() any {
		return (&item{}).init()
	},
}

type (
	// Item
	// 日志条目.
	Item interface {
		Copy() Item
		Level() base.Level
		Message() string
		ParentSpan() (SpanId, int32)
		Release()
		Span() (SpanId, int32)
		Stack() Stack
		String() string
		Time() time.Time
		TraceId() TraceId
	}

	item struct {
		time    time.Time
		level   base.Level
		message string

		spanId, parentSpanId             SpanId
		spanPosition, parentSpanPosition int32
		traceId                          TraceId

		stack Stack
	}
)

// NewItem
// 取出池内对象，并初始化.
func NewItem(ctx context.Context, level base.Level, message string) Item {
	// 1. 基础参数.
	o := itemPool.Get().(*item).reset(ctx)
	o.level = level
	o.message = message

	// 2. 堆栈参数.
	if level.IsFatal() {
		o.stack = NewStack()
	}
	return o
}

// Copy
// 复制日志条目实例.
func (o *item) Copy() Item {
	v := itemPool.Get().(*item)
	v.level, v.message, v.time = o.level, o.message, o.time
	v.spanId, v.parentSpanId = o.spanId, o.parentSpanId
	v.spanPosition, v.parentSpanPosition = o.spanPosition, o.parentSpanPosition
	v.traceId, v.stack = o.traceId, o.stack
	return v
}

func (o *item) Level() base.Level           { return o.level }
func (o *item) Message() string             { return o.message }
func (o *item) ParentSpan() (SpanId, int32) { return o.parentSpanId, o.parentSpanPosition }
func (o *item) Release()                    { o.unset(); itemPool.Put(o) }
func (o *item) Span() (SpanId, int32)       { return o.spanId, o.spanPosition }
func (o *item) Stack() Stack                { return o.stack }
func (o *item) String() string              { return o.message }
func (o *item) Time() time.Time             { return o.time }
func (o *item) TraceId() TraceId            { return o.traceId }

// +------------------------------------------------------------------------------+
// | Access methods                                                               |
// +------------------------------------------------------------------------------+

func (o *item) init() *item {
	return o
}

func (o *item) reset(ctx context.Context) *item {
	// 1. 时间参数.
	o.time = time.Now()

	// 2. 链路信息.
	if ctx != nil {
		if v := GetContextTracing(ctx); v != nil {
			o.spanId, o.spanPosition = v.GetSpanAndIncrement()
			o.parentSpanId, o.parentSpanPosition = v.GetParent()
			o.traceId = v.GetTraceId()
		}
	}
	return o
}

func (o *item) unset() {
	o.message, o.stack = "", nil
	o.spanId, o.parentSpanId = nil, nil
	o.spanPosition, o.parentSpanPosition = 0, 0
	o.traceId = nil
}
